home *** CD-ROM | disk | FTP | other *** search
- /* Copyright (C) 1999, 2000 Aladdin Enterprises. All rights reserved.
-
- This file is part of AFPL Ghostscript.
-
- AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author or
- distributor accepts any responsibility for the consequences of using it, or
- for whether it serves any particular purpose or works at all, unless he or
- she says so in writing. Refer to the Aladdin Free Public License (the
- "License") for full details.
-
- Every copy of AFPL Ghostscript must include a copy of the License, normally
- in a plain ASCII text file named PUBLIC. The License grants you the right
- to copy, modify and redistribute AFPL Ghostscript, but only under certain
- conditions described in the License. Among other things, the License
- requires that the copyright notice and this notice be preserved on all
- copies.
- */
-
- /*$Id: gdevpdff.c,v 1.8.2.1 2000/11/09 20:40:29 rayjj Exp $ */
- /* Font handling for pdfwrite driver. */
- #include "ctype_.h"
- #include "math_.h"
- #include "memory_.h"
- #include "string_.h"
- #include "gx.h"
- #include "gserrors.h"
- #include "gsmalloc.h" /* for patching font memory */
- #include "gsmatrix.h"
- #include "gspath.h"
- #include "gsutil.h" /* for bytes_compare */
- #include "gxfixed.h" /* for gxfcache.h */
- #include "gxfont.h"
- #include "gxfcache.h" /* for orig_fonts list */
- #include "gxpath.h" /* for getting current point */
- #include "gdevpdfx.h"
- #include "gdevpdff.h"
- #include "gdevpdfo.h"
- #include "gdevpsf.h"
- #include "scommon.h"
-
- /*
- * In our quest to work around Acrobat Reader quirks, we're resorting to
- * making all font names in the output unique by adding a suffix derived
- * from the PDF object number. We hope to get rid of this someday....
- */
- static bool MAKE_FONT_NAMES_UNIQUE = true;
-
- /* GC descriptors */
- public_st_pdf_font();
- public_st_pdf_char_proc();
- public_st_pdf_font_descriptor();
- private_st_pdf_encoding_element();
- private ENUM_PTRS_WITH(pdf_encoding_elt_enum_ptrs, pdf_encoding_element_t *pe) {
- uint count = size / (uint)sizeof(*pe);
-
- if (index >= count)
- return 0;
- return ENUM_CONST_STRING(&pe[index].str);
- } ENUM_PTRS_END
- private RELOC_PTRS_WITH(pdf_encoding_elt_reloc_ptrs, pdf_encoding_element_t *pe)
- uint count = size / (uint)sizeof(*pe);
- uint i;
-
- for (i = 0; i < count; ++i)
- RELOC_CONST_STRING_VAR(pe[i].str);
- RELOC_PTRS_END
-
- /* Define the 14 standard built-in fonts. */
- const pdf_standard_font_t pdf_standard_fonts[] = {
- #define m(name, enc) {name, enc},
- pdf_do_std_fonts(m)
- #undef m
- {0}
- };
-
- /* ---------------- Embedding status ---------------- */
-
- /* Return the index of a standard font name, or -1 if missing. */
- int
- pdf_find_standard_font(const byte *str, uint size)
- {
- const pdf_standard_font_t *ppsf;
-
- for (ppsf = pdf_standard_fonts; ppsf->fname; ++ppsf)
- if (strlen(ppsf->fname) == size &&
- !strncmp(ppsf->fname, (const char *)str, size)
- )
- return ppsf - pdf_standard_fonts;
- return -1;
- }
-
- /*
- * If there is a standard font with the same appearance (CharStrings,
- * Private, WeightVector) as the given font, set *psame to the mask of
- * identical properties, and return the standard-font index; otherwise,
- * set *psame to 0 and return -1.
- */
- private int
- find_std_appearance(const gx_device_pdf *pdev, const gs_font_base *bfont,
- int mask, int *psame)
- {
- bool has_uid = uid_is_UniqueID(&bfont->UID) && bfont->UID.id != 0;
- const pdf_std_font_t *psf = pdev->std_fonts;
- int i;
-
- mask |= FONT_SAME_OUTLINES;
- for (i = 0; i < PDF_NUM_STD_FONTS; ++psf, ++i) {
- if (has_uid) {
- if (!uid_equal(&bfont->UID, &psf->uid))
- continue;
- if (!psf->font) {
- /*
- * Identity of UIDs is supposed to guarantee that the
- * fonts have the same outlines and metrics.
- */
- *psame = FONT_SAME_OUTLINES | FONT_SAME_METRICS;
- return i;
- }
- }
- if (psf->font) {
- int same = *psame =
- bfont->procs.same_font((const gs_font *)bfont, psf->font,
- mask);
-
- if (same & FONT_SAME_OUTLINES)
- return i;
- }
- }
- *psame = 0;
- return -1;
- }
-
- /*
- * We register the fonts in pdev->std_fonts so that the pointers can
- * be weak (get set to 0 when the font is freed).
- */
- private GS_NOTIFY_PROC(pdf_std_font_notify_proc);
- typedef struct pdf_std_font_notify_s {
- gx_device_pdf *pdev;
- int index; /* in std_fonts */
- gs_font *font; /* for checking */
- } pdf_std_font_notify_t;
- gs_private_st_ptrs2(st_pdf_std_font_notify, pdf_std_font_notify_t,
- "pdf_std_font_notify_t",
- pdf_std_font_notify_enum_ptrs,
- pdf_std_font_notify_reloc_ptrs,
- pdev, font);
- private int
- pdf_std_font_notify_proc(void *vpsfn /*proc_data*/, void *event_data)
- {
- pdf_std_font_notify_t *const psfn = vpsfn;
- gx_device_pdf *const pdev = psfn->pdev;
- gs_font *const font = psfn->font;
-
- if (event_data)
- return 0; /* unknown event */
- if_debug4('_',
- "[_] notify 0x%lx: gs_font 0x%lx, id %ld, index=%d\n",
- (ulong)psfn, (ulong)font, font->id, psfn->index);
- #ifdef DEBUG
- if (pdev->std_fonts[psfn->index].font != font)
- lprintf3("pdf_std_font_notify font = 0x%lx, std_fonts[%d] = 0x%lx\n",
- (ulong)font, psfn->index,
- (ulong)pdev->std_fonts[psfn->index].font);
- else
- #endif
- pdev->std_fonts[psfn->index].font = 0;
- gs_font_notify_unregister(font, pdf_std_font_notify_proc, vpsfn);
- gs_free_object(pdev->pdf_memory, vpsfn, "pdf_std_font_notify_proc");
- return 0;
- }
-
- /* Unregister the standard fonts when cleaning up. */
- private void
- pdf_std_font_unreg_proc(void *vpsfn /*proc_data*/)
- {
- pdf_std_font_notify_proc(vpsfn, NULL);
- }
- void
- pdf_unregister_fonts(gx_device_pdf *pdev)
- {
- int j;
-
- for (j = 0; j < PDF_NUM_STD_FONTS; ++j)
- if (pdev->std_fonts[j].font != 0)
- gs_notify_unregister_calling(&pdev->std_fonts[j].font->notify_list,
- pdf_std_font_notify_proc, NULL,
- pdf_std_font_unreg_proc);
- }
-
- /*
- * Scan a font directory for standard fonts. Return true if any new ones
- * were found.
- */
- private bool
- scan_for_standard_fonts(gx_device_pdf *pdev, const gs_font_dir *dir)
- {
- bool found = false;
- gs_font *orig = dir->orig_fonts;
-
- for (; orig; orig = orig->next) {
- gs_font_base *obfont;
-
- if (orig->FontType == ft_composite || !orig->is_resource)
- continue;
- obfont = (gs_font_base *)orig;
- if (uid_is_UniqueID(&obfont->UID)) {
- /* Is it one of the standard fonts? */
- int i = pdf_find_standard_font(orig->key_name.chars,
- orig->key_name.size);
-
- if (i >= 0 && pdev->std_fonts[i].font == 0) {
- pdf_std_font_notify_t *psfn =
- gs_alloc_struct(pdev->pdf_memory, pdf_std_font_notify_t,
- &st_pdf_std_font_notify,
- "scan_for_standard_fonts");
-
- if (psfn == 0)
- continue; /* can't register */
- psfn->pdev = pdev;
- psfn->index = i;
- psfn->font = orig;
- if_debug4('_',
- "[_]register 0x%lx: gs_font 0x%lx, id %ld, index=%d\n",
- (ulong)psfn, (ulong)orig, orig->id, i);
- gs_font_notify_register(orig, pdf_std_font_notify_proc, psfn);
- pdev->std_fonts[i].uid = obfont->UID;
- pdev->std_fonts[i].orig_matrix = obfont->FontMatrix;
- pdev->std_fonts[i].font = orig;
- found = true;
- }
- }
- }
- return found;
- }
-
- /*
- * Determine the embedding status of a font. If the font is in the base
- * 14, store its index (0..13) in *pindex, otherwise store -1 there.
- */
- private bool
- font_is_symbolic(const gs_font *font)
- {
- if (font->FontType == ft_composite)
- return true; /* arbitrary */
- switch (((const gs_font_base *)font)->nearest_encoding_index) {
- case ENCODING_INDEX_STANDARD:
- case ENCODING_INDEX_ISOLATIN1:
- case ENCODING_INDEX_WINANSI:
- case ENCODING_INDEX_MACROMAN:
- return false;
- default:
- return true;
- }
- }
- private bool
- embed_list_includes(const gs_param_string_array *psa, const byte *chars,
- uint size)
- {
- uint i;
-
- for (i = 0; i < psa->size; ++i)
- if (!bytes_compare(psa->data[i].data, psa->data[i].size, chars, size))
- return true;
- return false;
- }
- pdf_font_embed_t
- pdf_font_embed_status(gx_device_pdf *pdev, gs_font *font, int *pindex,
- int *psame)
- {
- const byte *chars = font->font_name.chars;
- uint size = font->font_name.size;
-
- /*
- * The behavior of Acrobat Distiller changed between 3.0 (PDF 1.2),
- * which will never embed the base 14 fonts, and 4.0 (PDF 1.3), which
- * doesn't treat them any differently from any other fonts.
- */
- #if 0 /**************** DOESN'T WORK ****************/
- if (pdev->CompatibilityLevel < 1.3) {
- #else
- {
- #endif
- /* Check whether the font is in the base 14. */
- int index = pdf_find_standard_font(chars, size);
-
- if (index >= 0) {
- *pindex = index;
- if (font->is_resource) {
- *psame = ~0;
- return FONT_EMBED_STANDARD;
- } else if (font->FontType != ft_composite &&
- find_std_appearance(pdev, (gs_font_base *)font, -1,
- psame) == index)
- return FONT_EMBED_STANDARD;
- }
- }
- *pindex = -1;
- *psame = 0;
- /* Check the Embed lists. */
- if (embed_list_includes(&pdev->params.NeverEmbed, chars, size))
- return FONT_EMBED_NO;
- if (pdev->params.EmbedAllFonts || font_is_symbolic(font) ||
- embed_list_includes(&pdev->params.AlwaysEmbed, chars, size))
- return FONT_EMBED_YES;
- return FONT_EMBED_NO;
- }
-
- /* ---------------- Everything else ---------------- */
-
- /*
- * Find the original (unscaled) standard font corresponding to an
- * arbitrary font, if any. Return its index in standard_fonts, or -1.
- */
- int
- pdf_find_orig_font(gx_device_pdf *pdev, gs_font *font, gs_matrix *pfmat)
- {
- bool scan = true;
- int i;
-
- if (font->FontType == ft_composite)
- return -1;
- for (;; font = font->base) {
- gs_font_base *bfont = (gs_font_base *)font;
- int same;
-
- /* Look for a standard font with the same appearance. */
- i = find_std_appearance(pdev, bfont, 0, &same);
- if (i >= 0)
- break;
- if (scan) {
- /* Scan for fonts with any of the standard names that */
- /* have a UID. */
- bool found = scan_for_standard_fonts(pdev, font->dir);
-
- scan = false;
- if (found) {
- i = find_std_appearance(pdev, bfont, 0, &same);
- if (i >= 0)
- break;
- }
- }
- if (font->base == font)
- return -1;
- }
- *pfmat = pdev->std_fonts[i].orig_matrix;
- return i;
- }
-
- /*
- * Allocate a font resource. If descriptor_id is gs_no_id, no
- * FontDescriptor is allocated.
- */
- int
- pdf_alloc_font(gx_device_pdf *pdev, gs_id rid, pdf_font_t **ppfres,
- const pdf_font_descriptor_t *pfd_in)
- {
- gs_memory_t *mem = pdev->v_memory;
- pdf_font_descriptor_t *pfd = 0;
- gs_string chars_used, glyphs_used;
- int code;
- pdf_font_t *pfres;
-
- chars_used.data = 0;
- glyphs_used.data = 0;
- if (pfd_in != 0) {
- code = pdf_alloc_resource(pdev, resourceFontDescriptor,
- pfd_in->rid, (pdf_resource_t **)&pfd, 0L);
- if (code < 0)
- return code;
- chars_used.size = pfd_in->chars_used.size;
- chars_used.data = gs_alloc_string(mem, chars_used.size,
- "pdf_alloc_font(chars_used)");
- if (chars_used.data == 0)
- goto fail;
- memset(chars_used.data, 0, chars_used.size);
- pfd->values = pfd_in->values;
- pfd->chars_used = chars_used;
- pfd->glyphs_used = glyphs_used;
- pfd->subset_ok = true;
- pfd->FontFile_id = 0;
- pfd->base_font = 0;
- pfd->notified = false;
- pfd->written = false;
- }
- code = pdf_alloc_resource(pdev, resourceFont, rid,
- (pdf_resource_t **)ppfres, 0L);
- if (code < 0)
- goto fail;
- pfres = *ppfres;
- memset((byte *)pfres + sizeof(pdf_resource_t), 0,
- sizeof(*pfres) - sizeof(pdf_resource_t));
- sprintf(pfres->frname, "R%ld", pfres->object->id);
- pfres->index = -1;
- pfres->is_MM_instance = false;
- pfres->BaseEncoding = ENCODING_INDEX_UNKNOWN;
- pfres->Differences = 0;
- pfres->FontDescriptor = pfd;
- pfres->write_Widths = false;
- pfres->char_procs = 0;
- pfres->skip = false;
- return 0;
- fail:
- if (glyphs_used.data)
- gs_free_string(mem, glyphs_used.data, glyphs_used.size,
- "pdf_alloc_font(glyphs_used)");
- if (chars_used.data)
- gs_free_string(mem, chars_used.data, chars_used.size,
- "pdf_alloc_font(chars_used)");
- gs_free_object(mem, pfd, "pdf_alloc_font(descriptor)");
- return code;
- }
-
- /*
- * Determine whether a font is a subset font by examining the name.
- */
- bool
- pdf_has_subset_prefix(const byte *str, uint size)
- {
- int i;
-
- if (size < SUBSET_PREFIX_SIZE || str[SUBSET_PREFIX_SIZE - 1] != '+')
- return false;
- for (i = 0; i < SUBSET_PREFIX_SIZE - 1; ++i)
- if ((uint)(str[i] - 'A') >= 26)
- return false;
- return true;
- }
-
- /*
- * Make the prefix for a subset font from the font's resource ID.
- */
- void
- pdf_make_subset_prefix(byte *str, ulong id)
- {
- int i;
- ulong v;
-
- for (i = 0, v = id * 987654321; i < SUBSET_PREFIX_SIZE - 1; ++i, v /= 26)
- str[i] = 'A' + (v % 26);
- str[SUBSET_PREFIX_SIZE - 1] = '+';
- }
-
- /*
- * Adjust the FontName of a newly created FontDescriptor so that it is
- * unique if necessary.
- */
- int
- pdf_adjust_font_name(const gx_device_pdf *pdev, pdf_font_descriptor_t *pfd,
- bool is_standard)
- {
- int code = 0;
-
- if (MAKE_FONT_NAMES_UNIQUE) {
- /* Check whether this name has already been used. */
- int j = 0;
- pdf_font_descriptor_t *old;
- byte *chars = pfd->FontName.chars;
- uint size = pfd->FontName.size;
-
- #define SUFFIX_CHAR '~'
- /*
- * If the name looks as though it has one of our unique suffixes,
- * remove the suffix.
- */
- {
- int i;
-
- for (i = size;
- i > 0 && isxdigit(chars[i - 1]);
- --i)
- DO_NOTHING;
- if (i < size && i > 0 && chars[i - 1] == SUFFIX_CHAR) {
- do {
- --i;
- } while (i > 0 && chars[i - 1] == SUFFIX_CHAR);
- size = i + 1;
- }
- code = size != pfd->FontName.size;
- }
- /*
- * Non-standard fonts with standard names must always use a suffix
- * to avoid being confused with the standard fonts.
- */
- if (!is_standard)
- for (; j < NUM_RESOURCE_CHAINS; ++j)
- for (old = (pdf_font_descriptor_t *)pdev->resources[resourceFontDescriptor].chains[j];
- old != 0; old = old->next
- ) {
- const byte *old_chars = old->FontName.chars;
- uint old_size = old->FontName.size;
-
- if (old == pfd)
- continue;
- if (pdf_has_subset_prefix(old_chars, old_size))
- old_chars += SUBSET_PREFIX_SIZE,
- old_size -= SUBSET_PREFIX_SIZE;
- if (!bytes_compare(old_chars, old_size, chars, size))
- goto found;
- }
- found:
- if (j < NUM_RESOURCE_CHAINS) {
- /* Create a unique name. */
- char suffix[sizeof(long) * 2 + 2];
- uint suffix_size;
-
- sprintf(suffix, "%c%lx", SUFFIX_CHAR,
- pdf_resource_id((pdf_resource_t *)pfd));
- suffix_size = strlen(suffix);
- if (size + suffix_size > sizeof(pfd->FontName.chars))
- return_error(gs_error_rangecheck);
- memcpy(chars + size, (const byte *)suffix, suffix_size);
- size += suffix_size;
- code = 1;
- }
- pfd->FontName.size = size;
- #undef SUFFIX_CHAR
- }
- return code;
- }
-
- /* Add an encoding difference to a font. */
- int
- pdf_add_encoding_difference(gx_device_pdf *pdev, pdf_font_t *ppf, int chr,
- const gs_font_base *bfont, gs_glyph glyph)
- {
- pdf_encoding_element_t *pdiff = ppf->Differences;
-
- if (pdiff == 0) {
- pdiff = gs_alloc_struct_array(pdev->pdf_memory, 256,
- pdf_encoding_element_t,
- &st_pdf_encoding_element,
- "Differences");
- if (pdiff == 0)
- return_error(gs_error_VMerror);
- memset(pdiff, 0, sizeof(pdf_encoding_element_t) * 256);
- ppf->Differences = pdiff;
- }
- pdiff[chr].glyph = glyph;
- pdiff[chr].str.data = (const byte *)
- bfont->procs.callbacks.glyph_name(glyph, &pdiff[chr].str.size);
- return 0;
- }
-
- /* Get the width of a given character in a (base) font. */
- int
- pdf_char_width(pdf_font_t *ppf, int ch, gs_font *font,
- int *pwidth /* may be NULL */)
- {
- if (ch < 0 || ch > 255)
- return_error(gs_error_rangecheck);
- if (!(ppf->widths_known[ch >> 3] & (1 << (ch & 7)))) {
- gs_font_base *bfont = (gs_font_base *)font;
- gs_glyph glyph = bfont->procs.encode_char(font, (gs_char)ch,
- GLYPH_SPACE_INDEX);
- int wmode = font->WMode;
- gs_glyph_info_t info;
- double w, v;
- int code;
-
- if (glyph != gs_no_glyph &&
- (code = font->procs.glyph_info(font, glyph, NULL,
- GLYPH_INFO_WIDTH0 << wmode,
- &info)) >= 0
- ) {
- gs_const_string gnstr;
-
- if (wmode && (w = info.width[wmode].y) != 0)
- v = info.width[wmode].x;
- else
- w = info.width[wmode].x, v = info.width[wmode].y;
- if (v != 0)
- return_error(gs_error_rangecheck);
- if (font->FontType == ft_TrueType) {
- /* TrueType fonts have 1 unit per em, we want 1000. */
- w *= 1000;
- }
- ppf->Widths[ch] = (int)w;
- /*
- * If the character is .notdef, don't mark the width as known,
- * just in case this is an incrementally defined font.
- */
- gnstr.data = (const byte *)
- bfont->procs.callbacks.glyph_name(glyph, &gnstr.size);
- if (gnstr.size != 7 || memcmp(gnstr.data, ".notdef", 7))
- ppf->widths_known[ch >> 3] |= 1 << (ch & 7);
- } else {
- /* Try for MissingWidth. */
- static const gs_point tt_scale = {1000, 1000};
- const gs_point *pscale = 0;
- gs_font_info_t finfo;
-
- if (font->FontType == ft_TrueType) {
- /* TrueType fonts have 1 unit per em, we want 1000. */
- pscale = &tt_scale;
- }
- code = font->procs.font_info(font, pscale, FONT_INFO_MISSING_WIDTH,
- &finfo);
- if (code < 0)
- return code;
- ppf->Widths[ch] = finfo.MissingWidth;
- /*
- * Don't mark the width as known, just in case this is an
- * incrementally defined font.
- */
- }
- }
- if (pwidth)
- *pwidth = ppf->Widths[ch];
- return 0;
- }
-
- /*
- * Find the range of character codes that includes all the defined
- * characters in a font. This is a separate procedure only for
- * readability: it is only called from one place in pdf_update_text_state.
- */
- void
- pdf_find_char_range(gs_font *font, int *pfirst, int *plast)
- {
- gs_glyph notdef = gs_no_glyph;
- int first = 0, last = 255;
- gs_glyph glyph;
-
- switch (font->FontType) {
- case ft_encrypted:
- case ft_encrypted2: {
- /* Scan the Encoding vector looking for .notdef. */
- gs_font_base *const bfont = (gs_font_base *)font;
- int ch;
-
- for (ch = 0; ch <= 255; ++ch) {
- gs_glyph glyph =
- font->procs.encode_char(font, (gs_char)ch,
- GLYPH_SPACE_INDEX);
- gs_const_string gnstr;
-
- if (glyph == gs_no_glyph)
- continue;
- gnstr.data = (const byte *)
- bfont->procs.callbacks.glyph_name(glyph, &gnstr.size);
- if (gnstr.size == 7 && !memcmp(gnstr.data, ".notdef", 7)) {
- notdef = glyph;
- break;
- }
- }
- break;
- }
- default:
- DO_NOTHING;
- }
- while (last >= first &&
- ((glyph =
- font->procs.encode_char(font, (gs_char)last,
- GLYPH_SPACE_INDEX))== gs_no_glyph ||
- glyph == notdef || glyph == gs_min_cid_glyph)
- )
- --last;
- while (first <= last &&
- ((glyph =
- font->procs.encode_char(font, (gs_char)first,
- GLYPH_SPACE_INDEX))== gs_no_glyph ||
- glyph == notdef || glyph == gs_min_cid_glyph)
- )
- ++first;
- if (first > last)
- last = first; /* no characters used */
- *pfirst = first;
- *plast = last;
- }
-
- /* Compute the FontDescriptor.values for a font. */
- private int
- font_char_bbox(gs_rect *pbox, gs_glyph *pglyph, gs_font *font, int ch,
- const gs_matrix *pmat)
- {
- gs_glyph glyph;
- gs_glyph_info_t info;
- int code;
-
- glyph = font->procs.encode_char(font, (gs_char)ch, GLYPH_SPACE_INDEX);
- if (glyph == gs_no_glyph)
- return gs_error_undefined;
- code = font->procs.glyph_info(font, glyph, pmat, GLYPH_INFO_BBOX, &info);
- if (code < 0)
- return code;
- *pbox = info.bbox;
- if (pglyph)
- *pglyph = glyph;
- return 0;
- }
- int
- pdf_compute_font_descriptor(gx_device_pdf *pdev, pdf_font_descriptor_t *pfd,
- gs_font *font, const byte *used /*[32]*/)
- {
- gs_font_base *bfont = (gs_font_base *)font;
- gs_glyph glyph, notdef;
- int index;
- int wmode = font->WMode;
- int members = (GLYPH_INFO_WIDTH0 << wmode) |
- GLYPH_INFO_BBOX | GLYPH_INFO_NUM_PIECES;
- gs_glyph letters[52];
- int num_letters = 0;
- pdf_font_descriptor_values_t desc;
- gs_matrix smat;
- gs_matrix *pmat = NULL;
- int fixed_width = 0;
- int small_descent = 0, small_height = 0;
- int code;
-
- memset(&desc, 0, sizeof(desc));
- desc.FontType = font->FontType;
- desc.FontBBox.p.x = desc.FontBBox.p.y = max_int;
- desc.FontBBox.q.x = desc.FontBBox.q.y = min_int;
- /*
- * Embedded TrueType fonts use a 1000-unit character space, but the
- * font itself uses a 1-unit space. Compensate for this here.
- */
- if (font->FontType == ft_TrueType) {
- gs_make_scaling(1000.0, 1000.0, &smat);
- pmat = &smat;
- }
- /*
- * See the note on FONT_IS_ADOBE_ROMAN / FONT_USES_STANDARD_ENCODING
- * in gdevpdff.h for why the following substitution is made.
- */
- #if 0
- # define CONSIDER_FONT_SYMBOLIC(font) font_is_symbolic(font)
- #else
- # define CONSIDER_FONT_SYMBOLIC(font)\
- ((font)->FontType == ft_composite ||\
- ((const gs_font_base *)(font))->encoding_index != ENCODING_INDEX_STANDARD)
- #endif
- if (CONSIDER_FONT_SYMBOLIC(font))
- desc.Flags |= FONT_IS_SYMBOLIC;
- else {
- /*
- * Look at various specific characters to guess at the remaining
- * descriptor values (CapHeight, ItalicAngle, StemV, XHeight,
- * and flags SERIF, SCRIPT, ITALIC, ALL_CAPS, and SMALL_CAPS).
- * The algorithms are pretty crude.
- */
- /*
- * Look at the glyphs for the lower-case letters. If they are
- * all missing, this is an all-cap font; if any is present, check
- * the relative heights to determine whether this is a small-cap font.
- */
- bool small_present = false;
- int ch;
- int x_height = min_int;
- int cap_height = 0;
- gs_rect bbox, bbox2;
-
- desc.Flags |= FONT_IS_ADOBE_ROMAN; /* required if not symbolic */
- for (ch = 'a'; ch <= 'z'; ++ch) {
- int y0, y1;
-
- code =
- font_char_bbox(&bbox, &letters[num_letters], font, ch, pmat);
- if (code < 0)
- continue;
- ++num_letters;
- rect_merge(desc.FontBBox, bbox);
- small_present = true;
- y0 = (int)bbox.p.y;
- y1 = (int)bbox.q.y;
- switch (ch) {
- case 'b': case 'd': case 'f': case 'h':
- case 'k': case 'l': case 't': /* ascender */
- small_height = max(small_height, y1);
- case 'i': /* anomalous ascent */
- break;
- case 'j': /* descender with anomalous ascent */
- small_descent = min(small_descent, y0);
- break;
- case 'g': case 'p': case 'q': case 'y': /* descender */
- small_descent = min(small_descent, y0);
- default: /* no ascender or descender */
- x_height = max(x_height, y1);
- }
- }
- desc.XHeight = (int)x_height;
- if (!small_present)
- desc.Flags |= FONT_IS_ALL_CAPS;
- for (ch = 'A'; ch <= 'Z'; ++ch) {
- code =
- font_char_bbox(&bbox, &letters[num_letters], font, ch, pmat);
- if (code < 0)
- continue;
- ++num_letters;
- rect_merge(desc.FontBBox, bbox);
- cap_height = max(cap_height, (int)bbox.q.y);
- }
- desc.CapHeight = cap_height;
- /*
- * Look at various glyphs to determine ItalicAngle, StemV,
- * SERIF, SCRIPT, and ITALIC.
- */
- if ((code = font_char_bbox(&bbox, NULL, font, ':', pmat)) >= 0 &&
- (code = font_char_bbox(&bbox2, NULL, font, '.', pmat)) >= 0
- ) {
- /* Calculate the dominant angle. */
- int angle =
- (int)(atan2((bbox.q.y - bbox.p.y) - (bbox2.q.y - bbox2.p.y),
- (bbox.q.x - bbox.p.x) - (bbox2.q.x - bbox2.p.x)) *
- radians_to_degrees) - 90;
-
- /* Normalize to [-90..90]. */
- while (angle > 90)
- angle -= 180;
- while (angle < -90)
- angle += 180;
- if (angle < -30)
- angle = -30;
- else if (angle > 30)
- angle = 30;
- /*
- * For script or embellished fonts, we can get an angle that is
- * slightly off from zero even for non-italic fonts.
- * Compensate for this now.
- */
- if (angle <= 2 && angle >= -2)
- angle = 0;
- desc.ItalicAngle = angle;
- }
- if (desc.ItalicAngle)
- desc.Flags |= FONT_IS_ITALIC;
- if (code >= 0) {
- double wdot = bbox2.q.x - bbox2.p.x;
-
- if ((code = font_char_bbox(&bbox2, NULL, font, 'I', pmat)) >= 0) {
- double wcolon = bbox.q.x - bbox.p.x;
- double wI = bbox2.q.x - bbox2.p.x;
-
- desc.StemV = (int)wdot;
- if (wI > wcolon * 2.5 || wI > (bbox2.q.y - bbox2.p.y) * 0.25)
- desc.Flags |= FONT_IS_SERIF;
- }
- }
- }
- /*
- * Scan the entire glyph space to compute Ascent, Descent, FontBBox,
- * and the fixed width if any. Avoid computing the bounding box of
- * letters a second time.
- */
- num_letters = psf_sort_glyphs(letters, num_letters);
- desc.Ascent = desc.FontBBox.q.y;
- notdef = gs_no_glyph;
- for (index = 0;
- (code = font->procs.enumerate_glyph(font, &index, GLYPH_SPACE_INDEX, &glyph)) >= 0 &&
- index != 0;
- ) {
- gs_glyph_info_t info;
- gs_const_string gnstr;
-
- if (psf_sorted_glyphs_include(letters, num_letters, glyph)) {
- /* We don't need the bounding box. */
- code = font->procs.glyph_info(font, glyph, pmat,
- members - GLYPH_INFO_BBOX, &info);
- if (code < 0)
- return code;
- } else {
- code = font->procs.glyph_info(font, glyph, pmat, members, &info);
- if (code < 0)
- return code;
- rect_merge(desc.FontBBox, info.bbox);
- if (!info.num_pieces)
- desc.Ascent = max(desc.Ascent, info.bbox.q.y);
- }
- if (notdef == gs_no_glyph) {
- gnstr.data = (const byte *)
- bfont->procs.callbacks.glyph_name(glyph, &gnstr.size);
- if (gnstr.size == 7 && !memcmp(gnstr.data, ".notdef", 7)) {
- notdef = glyph;
- desc.MissingWidth = info.width[wmode].x;
- }
- }
- if (info.width[wmode].y != 0)
- fixed_width = min_int;
- else if (fixed_width == 0)
- fixed_width = info.width[wmode].x;
- else if (info.width[wmode].x != fixed_width)
- fixed_width = min_int;
- }
- if (code < 0)
- return code;
- if (desc.Ascent == 0)
- desc.Ascent = desc.FontBBox.q.y;
- desc.Descent = desc.FontBBox.p.y;
- if (!(desc.Flags & (FONT_IS_SYMBOLIC | FONT_IS_ALL_CAPS)) &&
- (small_descent > desc.Descent / 3 || desc.XHeight > small_height * 0.9)
- )
- desc.Flags |= FONT_IS_SMALL_CAPS;
- if (fixed_width > 0) {
- desc.Flags |= FONT_IS_FIXED_WIDTH;
- desc.AvgWidth = desc.MaxWidth = desc.MissingWidth = fixed_width;
- }
- if (desc.CapHeight == 0)
- desc.CapHeight = desc.Ascent;
- if (desc.StemV == 0)
- desc.StemV = (int)(desc.FontBBox.q.x * 0.15);
- pfd->values = desc;
- return 0;
- }
-